package app.modules.account.business.service;

import app.modules.account.constant.AccountLockConstants;
import app.modules.account.persistence.dao.UserRoleRelationDAO;
import app.modules.common.constant.CommonLockConstants;
import app.modules.security.business.service.role.IRoleService;
import app.modules.security.dto.web.role.WebRoleDTO;
import jasmine.framework.common.exception.DataNotFoundException;
import jasmine.framework.common.util.CheckUtil;
import jasmine.framework.common.util.CollectionUtil;
import jasmine.framework.common.util.batch.BatchMap;
import jasmine.framework.context.InitSupport;
import jasmine.framework.context.RuntimeProvider;
import jasmine.framework.lock.annotation.DistributedLock;
import jasmine.security.rbac.model.SecRole;
import jasmine.security.rbac.model.SecUserRoleRelation;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author mh.z
 */
@Service
public class UserRoleRelationService implements InitSupport, IUserRoleRelationService {
    private UserRoleRelationDAO userRoleRelationDAO;
    private IRoleService roleService;

    public UserRoleRelationService(UserRoleRelationDAO userRoleRelationDAO) {
        this.userRoleRelationDAO = userRoleRelationDAO;
    }

    @Override
    public void init(RuntimeProvider runtimeProvider) {
        this.roleService = runtimeProvider.getByType(IRoleService.class);
    }

    /**
     * 查询指定用户的所有已分配角色
     *
     * @param userId
     * @return
     */
    public List<WebRoleDTO> listAssignedResources(Long userId) {
        List<WebRoleDTO> recordList = userRoleRelationDAO.listAssignedRoles(userId);
        roleService.populateWebRoleDTOs(recordList);

        return recordList;
    }

    @Override
    public long countByRoleId(Long roleId) {
        return userRoleRelationDAO.countByRoleId(roleId);
    }

    /**
     * 分配角色
     *
     * @param userId
     * @param roleIds
     */
    @DistributedLock(category = AccountLockConstants.LOCK_CATEGORY_USER_ASSIGN_ROLES, key = CommonLockConstants.LOCK_KEY_TENANT)
    @Transactional(rollbackFor = Exception.class)
    public void assignRole(Long userId, List<Long> roleIds) {
        CheckUtil.notNull(userId, "userId null");
        CheckUtil.notNull(roleIds, "roleIds null");

        // 删除指定用户的所有角色分配关系
        userRoleRelationDAO.deleteByUserId(userId);

        if (CollectionUtil.isNotEmpty(roleIds)) {
            BatchMap<Long, SecRole> batchMap = new BatchMap<>(SecRole::getId, (keys) -> {
                return roleService.listByIds(keys);
            });
            batchMap.load(roleIds);

            List<SecUserRoleRelation> newRecordList = CollectionUtil.mapToList(roleIds, (roleId) -> {
                SecRole role = batchMap.get(roleId);
                if (role == null) {
                    throw new DataNotFoundException(SecRole.class, roleId);
                }

                SecUserRoleRelation newRecord = new SecUserRoleRelation();
                newRecord.setUserId(userId);
                newRecord.setRoleId(roleId);

                return newRecord;
            });

            // 保存用户和角色的分配关系
            userRoleRelationDAO.saveBatch(newRecordList);
        }
    }

}
